package ru.artyushov.fingers.junk;

import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import ru.artyushov.fingers.core.Preprocessor;
import ru.artyushov.fingers.core.SpecialPointsFilter;
import ru.artyushov.fingers.core.basic.LightnessBasedBinarizer;
import ru.artyushov.fingers.core.basic.SpecialPointsExtractor;
import ru.artyushov.fingers.core.basic.SpecialPointsFeatureSet;
import ru.artyushov.fingers.core.data.Fingerprint;
import ru.artyushov.fingers.core.filter.EdgeDeadEndsFilter;
import ru.artyushov.fingers.core.preprocessor.PatternBasedSkeletizer;
import ru.artyushov.fingers.core.preprocessor.SpuriousForkRemover;
import ru.artyushov.fingers.main.util.ImageConverters;
import ru.artyushov.fingers.ui.UiMainWindow;
import ru.artyushov.fingers.ui.callbacks.ImageSelectionListener;
import ru.artyushov.fingers.ui.callbacks.ImageViewedListener;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

public class MainWindowTest {

    private final LightnessBasedBinarizer binarizer = new LightnessBasedBinarizer();

    private final SpecialPointsExtractor extractor = new SpecialPointsExtractor();

    private List<Pair<Preprocessor, String>> preprocessorAndEffect = new LinkedList<Pair<Preprocessor, String>>(){{
        add(new ImmutablePair<Preprocessor, String>(new PatternBasedSkeletizer(), "Skeletized image"));
        add(new ImmutablePair<Preprocessor, String>(new SpuriousForkRemover(2), "Forks removed (threshold = 5px)"));
        add(new ImmutablePair<Preprocessor, String>(new SpuriousForkRemover(5), "Forks removed (threshold = 10px)"));
        add(new ImmutablePair<Preprocessor, String>(new SpuriousForkRemover(10), "Forks removed (threshold = 15px)"));
    }};

    public static void main(String[] args) {
        final UiMainWindow mainWindow = new UiMainWindow();
        final MainWindowTest test = new MainWindowTest();

        ImageSelectionListener imageSelectionListener = new ImageSelectionListener() {
            public void onImageSelected(String pathToFile) {
                try {
                    BufferedImage image = ImageIO.read(new File(pathToFile));
                    final List<Pair<BufferedImage, String>> imageQueue = test.getImageQueue(image);
                    mainWindow.showImage(image, "Initial image", new NextImageListener(imageQueue, mainWindow));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        };
        mainWindow.startAndShowFileChooser(imageSelectionListener);
    }

    private List<Pair<BufferedImage, String>> getImageQueue(BufferedImage firstImage) {
        List<Pair<BufferedImage, String>> result = new LinkedList<Pair<BufferedImage, String>>();

        Fingerprint initialFingerprint = binarizer.toFingerprint(firstImage);
        result.add(ImmutablePair.of(ImageConverters.fromFingerprint(initialFingerprint), "Binarized image"));

        Fingerprint current = initialFingerprint;
        for (Pair<Preprocessor, String> preprocessor : preprocessorAndEffect) {
            Fingerprint next = preprocessor.getLeft().workYourMagic(current);
            result.add(ImmutablePair.of(ImageConverters.fromFingerprint(next), preprocessor.getRight()));
            current = next;
        }

        final SpecialPointsFeatureSet specialPoints = extractor.extractFeatures(current);
        final BufferedImage image = ImageConverters.fromFingerprint(current);
        ImageConverters.overlayCircles(image, specialPoints.getForks(), 5, Color.RED.getRGB());
        ImageConverters.overlayCircles(image, specialPoints.getDeadEnds(), 5, Color.BLUE.getRGB());

        result.add(Pair.of(image, "Special points"));

        SpecialPointsFilter filter = new EdgeDeadEndsFilter();
        BufferedImage imageWithFilteredSpecialPoints = ImageConverters.fromFingerprint(current);
        ImageConverters.overlayCircles(imageWithFilteredSpecialPoints, specialPoints.getForks(), 5, Color.RED.getRGB());
        ImageConverters.overlayCircles(imageWithFilteredSpecialPoints, filter.filter(current, specialPoints.getDeadEnds()), 5, Color.BLUE.getRGB());
        result.add(Pair.of(imageWithFilteredSpecialPoints, "Filtered special points"));

        return result;
    }

    private static class NextImageListener implements ImageViewedListener {

        private final LinkedList<Pair<BufferedImage, String>> imageQueue = new LinkedList<Pair<BufferedImage, String>>();
        private final UiMainWindow mainWindow;

        public NextImageListener(List<Pair<BufferedImage, String>> imageQueue, UiMainWindow mainWindow) {
            this.imageQueue.addAll(imageQueue);
            this.mainWindow = mainWindow;
        }

        @Override
        public void onImageViewed(BufferedImage image) {
            final Pair<BufferedImage, String> imageAndDescription = imageQueue.pollFirst();
            if (imageAndDescription != null) {
                mainWindow.showImage(imageAndDescription.getLeft(), imageAndDescription.getRight(), this);
            } else {
                mainWindow.stop();
            }
        }
    }
}
